
use std::collections::{HashMap as Map};
use std::cmp::min;

//use rand;
//use rand::Rng;

use crossbeam;
use simple_parallel;

use common::*;

fn run_batch(n:usize,data:&Vec<Instance>, i1:usize,i2:usize,
                 uu:&mut Map<u32,Repr>, vv:&mut Map<u32,Repr>) -> f64 {

    let g = 0.005;
    let rate = 0.01;

    let mut ss = 0.0;

    for ii in i1..i2 {
        let i = &data[ii];
        let p = i.p;
        let q = i.q;
        let r = i.r;

        let mut pu = uu.get_mut(&p).unwrap();
        let mut qv = vv.get_mut(&q).unwrap();

        let rr = get_score(n, &pu,&qv);

        let err = r-rr;

        let mut t:Vec<f64> = Vec::new();
        for j in 0..n {
            t.push(qv.v[j]);
        }

        for j in 0..n {
            qv.v[j] += rate*(err*pu.v[j]-g*qv.v[j]);
        }
        for j in 0..n {
            pu.v[j] += rate*(err*t[j]-g*pu.v[j]);
        }

        ss += err*err;
    }

    ss
}

// pub fn run(n:usize,data:&Vec<Instance>, uu:&mut Map<u32,Repr>, vv:&mut Map<u32,Repr>) -> f64 {
//     let batch_size = 8192*8;
//     let nn = data.len()/batch_size+1;
//     let mut ss = 0.0;
//     for i in 0..nn {
//         let i1 = i*batch_size;
//         let i2 = min(i1+batch_size,data.len());
//         let mut xs:Vec<Instance> = Vec::new();
//         let mut uu_i:Map<u32,Repr> = Map::new();
//         let mut vv_i:Map<u32,Repr> = Map::new();
//         for ii in i1..i2 {
//             let instance = data[ii].clone();
//             let p = uu.get(&instance.p).unwrap();
//             let q = vv.get(&instance.q).unwrap();
//             uu_i.insert(instance.p,p.clone());
//             vv_i.insert(instance.q,q.clone());
//             xs.push(instance);
//         }
//
//         let err = run_data(n,&xs,&mut uu_i,&mut vv_i);
//         println!("err {}",err);
//         //println!("ss {}",ss);
//         println!("xs {}",xs.len());
//         for (u,r) in uu_i.iter() {
//             let rr = uu.get_mut(u).unwrap();
//             for j in 0..n {
//                 rr.v[j] += r.v[j];
//             }
//         }
//         for (v,r) in vv_i.iter() {
//             let rr = vv.get_mut(v).unwrap();
//             for j in 0..n {
//                 rr.v[j] += r.v[j];
//             }
//         }
//     }
//
//     let s = data.len() as f64;
//     (ss/s).sqrt()
// }



pub fn run(n:usize,data:&Vec<Instance>, uu:&mut Map<u32,Repr>, vv:&mut Map<u32,Repr>) -> f64 {

    let num = 6;
    let batch_size = data.len()/num;;
    let mut pool = simple_parallel::Pool::new(num);

    //let mut ns = vec![0 as usize;num];
    //let mut rng = rand::thread_rng();
    //for j in 0..num-1 {
    //    let i = rng.next_u32() as usize%data.len();
    //    ns[j+1] = i;
    //}
    //ns.sort();
    //println!("{:?}",ns);

    // 多线程
    let xs:Vec<(usize,(f64,Map<u32,Repr>,Map<u32,Repr>))> = crossbeam::scope(|scope| {
        pool.unordered_map(scope, (0..num), |i| {
            let i1 = i*batch_size;
            let i2 = {if num-1 > i {i1+batch_size} else {data.len()}};
            //let i1 = ns[i];
            //let i2 = {if num-1 > i {ns[i+1]} else {data.len()}};
            //min(i1+batch_size,data.len());

            // let mut uu_i:Map<u32,Repr> = Map::new();
            // let mut vv_i:Map<u32,Repr> = Map::new();
            // for ii in i1..i2 {
            //     let instance = &data[ii];
            //     let p = uu.get(&instance.p).unwrap();
            //     let q = vv.get(&instance.q).unwrap();
            //     uu_i.insert(instance.p,p.clone());
            //     vv_i.insert(instance.q,q.clone());
            // }

            let mut uu_i = uu.clone();
            let mut vv_i = vv.clone();

            //(uu_i,vv_i)
            let ss = run_batch(n,&data,i1,i2,&mut uu_i, &mut vv_i);
            (ss,uu_i,vv_i)
        }).collect()
    });

    for (_,r) in uu.iter_mut() {
       r.v = vec![0.0 as f64;n];
    }
    for (_,r) in vv.iter_mut() {
       r.v = vec![0.0 as f64;n];
    }

    let mut ss = 0.0;
    for (_,(ss_i,uu_i,vv_i)) in xs {
        ss += ss_i;
        //println!("ss_i {}",ss_i);
        //println!("uu_i,{},vv_i,{}",uu_i.len(),vv_i.len());
        for (u,r) in uu_i.iter() {
            let rr = uu.get_mut(u).unwrap();
            for j in 0..n {
                rr.v[j] += (r.v[j])/(num as f64);
            }
        }
        for (v,r) in vv_i.iter() {
            let rr = vv.get_mut(v).unwrap();
            for j in 0..n {
                rr.v[j] += (r.v[j])/(num as f64);
            }
        }
    }

    let s = data.len() as f64;
    (ss/s).sqrt()
    //ss
}
